Repository navigation
Run coding_tools_env verification outside the notebook kernel - #1580
zuraiz-anjum wants to merge 2 commits into
Conversation
E2BSandbox.run_shell sends a subprocess.run cell to the code-interpreter kernel, and the verify commands, the reward file clear and the reward file read all went through that kernel. Their results then depended on kernel state: a rebound subprocess.run or pathlib.Path.read_text, a changed working directory or an edited os.environ. Add E2BSandbox.run_command, ported from jupyter_env (openenv#1233). It runs a command as its own process through E2B's process API, as root in /home/user, and reports the real exit status. A non-zero exit becomes a failed result; a command that cannot be started or a wait that ends without an exit status is raised after a best effort kill, so it is not scored. Verification and the reward read now use it. The agent's bash tool and the setup commands keep using run_shell. Refs openenv#1232
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 207c821. Configure here.
run_command joins stdout and stderr into output, so a login profile that prints to stderr broke a valid reward override and scoring fell back to the pass rate. jupyter_env parses stdout alone; do the same.
|
The |

Summary
Ports #1233 to
coding_tools_env. Verify commands, the reward file clear and the reward file read went through the code-interpreter kernel (run_shellsends asubprocess.runcell,read_fileaPath.read_textcell), so their results depended on kernel state. They now run as their own sandbox processes through E2B's process API, the wayjupyter_envdoes since #1233.Refs #1232
Type of Change
Alignment Checklist
Before submitting, verify:
.claude/docs/PRINCIPLES.mdand this PR aligns with our principles.claude/docs/INVARIANTS.mdand no invariants are violated/pre-submit-pr(orbash .claude/hooks/lint.shand tests) and addressed all issuesRFC Status
Details
E2BSandbox.run_commandis thejupyter_envone with the same rules: it starts the command withbackground=Trueasrootin/home/userand waits on the handle. A non-zero exit (CommandExitException, matched by itsexit_code) is a failed result. A command that cannot be started, or a wait that ends without an exit status, is raised after a best effort kill, so it is never scored.ToolResultin the shaperun_shelluses here (stdout and stderr joined,error="exit_code=N"), soverify_resultslook the same as before. Its default timeout is 30 s likerun_shell; verify commands still pass 120 s._run_verify_commandsuses it for themkdir, the clear and each verify command, and_read_reward_overridereads the file withcatthrough it instead ofread_file.bashand file tools and the setup commands are unchanged, so nothing the agent sees changes.Where this differs from
jupyter_env:run_shellhere already reported real exit codes, so honest scoring doesn't change.TimeoutExpired). Now, as injupyter_env, it is raised: no reward, and the episode doesn't finish. A hung test run is common in coding tasks, so say if you'd rather keep counting it as a failure here.Same limit as #1233: this is not an isolation boundary. E2B starts commands as
bash -l -c, so abashcall that writes anEXITtrap into/root/.bash_profilemakes a failing verify command pass. A test pins that, and the README says so. Onmainthe same root shell can already rewrite the tests, aconftest.pyor/bin/sh, so it isn't a new class of problem; #1232 tracks the fix.Test Plan
New tests in
tests/envs/test_coding_tools_environment.pydrive the realE2BSandboxagainst a stand-in kernel (cells run with a namespace that persists) and a stand-in process API (each command a freshbash -l -cwith a real exit status), with/home/userand/rootmapped to temp dirs:subprocess.runreaches the kernel: bothexit 1verify commands still fail and the reward is0.0. No verify command reaches the kernel.Path.read_textto return"1.0"; a verify command that writes0.8yields0.8.os.chdir;pwdin verification still reports the notebook dir. Every call goes out in the background, asroot, in/home/user, and the verify command keeps its 120 s timeout.run_commandunit tests, as in Run jupyter_env verification outside the notebook kernel #1233: non-zero exit, wait failure plus kill (also when the kill returnsFalseor raises), start failure, ande2b.CommandExitExceptionitself.donefalse.bashtool writes a poisoned/root/.bash_profileand a failing verify command passes (the limit above).run_command, notrun_shell; the reward file fake now answers both.PYTHONPATH=src:envs pytest tests/envs/test_coding_tools_environment.py, withe2b2.21.0 ande2b-code-interpreter2.6.2 as locked inenvs/coding_tools_env/uv.lock:mainwith only the new tests: the 11 new or changed cases fail, the other 13 pass.tests/envs/test_jupyter_environment.pystill passes.maintoo and guards this port: the reward file is parsed from stdout alone, so a login profile that prints to stderr cannot turn a valid override into a fallback to the pass rate.usort check,ruff format --checkandruff checkare clean on the test file, andruff checkon the env files. The two env files were notruff formatclean onmain; I left those lines alone, and the findings on them are the same as onmain.scripts/sync_env_docs.py --checkpasses after refreshing the docs stub.Not run against a live E2B sandbox. With an
E2B_API_KEY, this checks the change and the user and directory assumption in one go:Out of scope
terminus_envhas the same kernel path; Update Terminus env harness and sandbox backends #729 rewrites itse2b_sandbox.py, so I left it alone.submit_pathsdesign from Verify sandbox environments outside the agent's sandbox #1232.Note
Medium Risk
Changes reward/verification semantics (timeouts and sandbox failures no longer score as failed tests) and touches training-critical scoring paths, though agent-facing tools are unchanged.
Overview
Moves coding_tools_env verification off the Jupyter code-interpreter kernel so scoring cannot be forged by kernel tampering (e.g. rebinding
subprocess.runorPath.read_text, changingos.chdir).E2BSandboxgainsrun_command, which starts shell work through E2B’s process API asrootin/home/user, handles real exit codes, and raises (with a best-effort kill) when the command never exits—timeouts used to look like a failed verify._run_verify_commandsand reward-file clear/read now userun_commandinstead ofrun_shell/read_file; the reward override is parsed from stdout only so login-shell stderr from profiles does not break parsing.Docs spell out that this decouples verification from kernel state but does not isolate it from the agent (same sandbox, login-shell profiles—tracked in #1232). A large test suite pins kernel-immune scoring, timeout/error behavior, and the remaining profile-poisoning gap.
Reviewed by Cursor Bugbot for commit 72277ec. Bugbot is set up for automated code reviews on this repo. Configure here.